package com.framework.auth.common.log;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
@Slf4j
@Aspect
@Lazy
@Component
@Order(1)
public class LogAspect {
    private static final int MAX_SIZE = 2000;

    @Pointcut("@annotation(com.framework.auth.common.log.LogAnnotation)")
    public void saveLog() {

    }

    @Around("saveLog()")
    public Object saveLog(final ProceedingJoinPoint point) throws Throwable {
        LogBean logBean = new LogBean();
        logBean.setRequestTime(parseDateStr(new Date(), "YYYY-MM-dd HH:mm:ss"));
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //获取注解的参数值
        LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
        String logEven = "";
        if (logAnnotation != null) {
            if (isEmptyStr(logAnnotation.logEven())) {
                // 注解上的描述
                logEven = logAnnotation.logEven();
            } else {
                logEven = humpToUnderline(method.getName());
            }
        }
        // 请求的方法名
        String className = point.getTarget().getClass().getName();
        String methodName = signature.getName();
        Object[] args = point.getArgs();
        logBean.setParams(this.GetRequestData(point));
       // logBean.setApi(SessionInfo.getRequest() == null ? null : SessionInfo.getRequest().getRequestURI());
        logBean.setLogEvent(logEven);
        logBean.setObjMethod(className + "." + methodName);
        logBean.setServerIp(getLocalIP());
        //获取用户信息
        /*logBean.setRequestId(SessionInfo.getToken());
        if (StringUtil.isNotEmpty(logBean.getRequestId())) {
            logBean.setCurrentSessionUserName(SessionInfo.getCurrentSessionRealNameForLog());
            logBean.setCurrentSessionUserId(SessionInfo.getCurrentSessionUserIdForLog());
        }*/
        Object result = null;
        try {
            result = point.proceed(args);
            logBean.setSuccess(true);
            if (logAnnotation.isSaveResponseData()) {
                logBean.setResult(JSON.toJSONString(result));
            }
            logBean.setResponeTime(parseDateStr(new Date(), "YYYY-MM-dd HH:mm:ss"));
        } catch (Throwable throwable) {
            logBean.setSuccess(false);
            logBean.setError(getStackTrace(throwable));
            logBean.setResponeTime(parseDateStr(new Date(), "YYYY-MM-dd HH:mm:ss"));
            throw throwable;
        } finally {
            if (logBean.isSuccess()) {
                log.info(JSON.toJSONString(logBean));
            } else {
                log.error(JSON.toJSONString(logBean));
            }
        }
        return result;
    }

    public static String getStackTrace(Throwable throwable) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);

        try {
            throwable.printStackTrace(pw);
            return sw.toString();
        } finally {
            pw.close();
        }
    }

    private String GetRequestData(ProceedingJoinPoint joinPoint) {
        try {
            Object[] args = joinPoint.getArgs();
            if (args.length == 0) {
                return null;
            }
            Object[] parameter = new Object[args.length];
            int index = 0;
            for (Object object : args) {
                if (object instanceof HttpServletRequest) {
                    continue;
                }
                if (object instanceof HttpServletResponse) {
                    continue;
                }
                parameter[index] = object;
                index++;
            }
            String requestData = JSON.toJSONString(parameter);
           // String requestData = JacksonUtil.toJsonWithFormat(parameter);
            //String requestData = BeanUtil.transObj2Json(parameter);
            if (requestData.length() > MAX_SIZE) {
                requestData = requestData.substring(MAX_SIZE);
            }

            return requestData;
        } catch (Exception e) {
            log.error("获取响应数据,出现错误={}", e.getMessage(), e);
        }
        return null;
    }

    /**
     * 获取本地IP地址
     */
    public static String getLocalIP() {
        try {
            if (isWindowsOS()) {
                return InetAddress.getLocalHost().getHostAddress();
            } else {
                return getLinuxLocalIp();
            }

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断操作系统是否是Windows
     *
     * @return
     */
    public static boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
            isWindowsOS = true;
        }
        return isWindowsOS;
    }

    /**
     * 获取本地Host名称
     */
    public static String getLocalHostName() throws UnknownHostException {
        return InetAddress.getLocalHost().getHostName();
    }

    /**
     * 获取Linux下的IP地址
     *
     * @return IP地址
     * @throws SocketException
     */
    private static String getLinuxLocalIp() throws SocketException {
        String ip = "";
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                NetworkInterface intf = en.nextElement();
                String name = intf.getName();
                if (!name.contains("docker") && !name.contains("lo")) {
                    for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                        InetAddress inetAddress = enumIpAddr.nextElement();
                        if (!inetAddress.isLoopbackAddress()) {
                            String ipaddress = inetAddress.getHostAddress().toString();
                            if (!ipaddress.contains("::") && !ipaddress.contains("0:0:") && !ipaddress.contains("fe80")) {
                                ip = ipaddress;
                                System.out.println(ipaddress);
                            }
                        }
                    }
                }
            }
        } catch (SocketException ex) {
            System.out.println("获取ip地址异常");
            ip = "127.0.0.1";
            ex.printStackTrace();
        }
        System.out.println("IP:" + ip);
        return ip;
    }

    /**
     * 把驼峰命名的方法转换成大写下划线分割
     *
     * @param para
     * @return
     */
    public static String humpToUnderline(String para) {
        StringBuilder sb = new StringBuilder(para);
        int temp = 0;//定位
        if (!para.contains("_")) {
            for (int i = 0; i < para.length(); i++) {
                if (Character.isUpperCase(para.charAt(i))) {
                    sb.insert(i + temp, "_");
                    temp += 1;
                }
            }
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 字符串判断是否空
     *
     * @param str
     * @return
     */
    public static Boolean isEmptyStr(String str) {
        if (str == null || "null".equals(str) || "NULL".equals(str) || str.length() == 0) {
            return false;
        }
        if (str.trim() == null || str.trim().equals("") || str.trim().equals(" ")) {
            return false;
        }
        if (str.trim().equals("undefined") || str.trim().equals("[{}]") || str.trim().equals("[]")) {
            return false;
        }
        return true;
    }

    public static String parseDateStr(Date date, String pattern) {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        String dateStr;
        if (date == null) {
            return null;
        }
        dateStr = format.format(date);
        return dateStr;
    }
}
